package com.atguigu.ssyx.cart.service.impl;

import com.atguigu.ssyx.cart.service.CartInfoService;
import com.atguigu.ssyx.client.product.ProductFeignClient;
import com.atguigu.ssyx.common.constant.RedisConst;
import com.atguigu.ssyx.common.exception.SsyxException;
import com.atguigu.ssyx.common.result.ResultCodeEnum;
import com.atguigu.ssyx.enums.SkuType;
import com.atguigu.ssyx.model.order.CartInfo;
import com.atguigu.ssyx.model.product.SkuInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Created with IntelliJ IDEA.
 * ClassName: CartInfoServiceImpl
 * Package: com.atguigu.ssyx.cart.service.impl
 * Description:
 * User: fzykd
 *
 * @Author: LQH
 * Date: 2023-10-05
 * Time: 10:39
 */

@Service
public class CartInfoServiceImpl implements CartInfoService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    //返回购物车redis的key
    private String getCartKey(Long userId) {
        //user:userId:cart
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }

    //添加商品到购物车
    //添加内容 当前登录用户Id skuId 商品数据
    @Override
    public void addToCart(Long userId, Long skuId, Integer skuNum) {
        //1.因为购物车的数据都是存在redis中
        //从redis里面根据key获取数据 这个key包含userId
        String cartKey = this.getCartKey(userId);
        //Key <skuId,cartInfo>
        BoundHashOperations<String, String, CartInfo>
                //boundHashOps 操作的是hash类型 参数是key
                hashOps = redisTemplate.boundHashOps(cartKey);
        //2.根据第一步查询的结果 得到是skuId + skuNum关系
        //目的 判断是否第一次添加商品到购物车
        //进行判断，判断结果里面是否有skuId
        CartInfo cartInfo = null;
        if (hashOps.hasKey(skuId.toString())) {
            //3.如果结果里面保函skuId 不是第一次添加
            //3.1 根据skuId 获取数量 然后更新数据 +1
            //细节问题 限量问题 Map根据key获取val值 val类型是cartInfo
            cartInfo = hashOps.get(skuId.toString());
            //把购物车存在商品之前的数量获取数量 在进行更新操作
            Integer currentSkuNum = cartInfo.getSkuNum() + skuNum;
            //变成0之后 有删除数据的接口
            if (currentSkuNum < 1){
                return;
            }
            //更新cartInfo对象
            cartInfo.setSkuNum(currentSkuNum);
            cartInfo.setCurrentBuyNum(currentSkuNum);
            //判断购买商品数量不能大于限购数量   getPerLimit限购数量
            Integer perLimit = cartInfo.getPerLimit();
            if (currentSkuNum > perLimit){
                throw new SsyxException(ResultCodeEnum.SKU_LIMIT_ERROR);
            }
            //默认被选中 加入购物车 默认是都被选中
            //更新其他的值 默认都选中
            cartInfo.setIsChecked(1);
            //更新操作时间
            cartInfo.setUpdateTime(new Date());
        } else {
            //4.如果结果里面没有skuId 就是第一次添加
            //直接添加
            skuNum = 1;
            //封装CartInfo对象
            cartInfo = new CartInfo();
            //cartInfo里面大多属性都是sku信息
            //得到sku的信息 远程调用
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            //查询的数据 后面要使用 一定要有一个非空判断
            if (skuInfo == null){
                throw new SsyxException(ResultCodeEnum.DATA_ERROR);
            }
            //封装对象
            cartInfo.setSkuId(skuId);
            cartInfo.setCategoryId(skuInfo.getCategoryId());
            cartInfo.setSkuType(skuInfo.getSkuType());
            cartInfo.setIsNewPerson(skuInfo.getIsNewPerson());
            cartInfo.setUserId(userId);
            cartInfo.setCartPrice(skuInfo.getPrice());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setCurrentBuyNum(skuNum);
            cartInfo.setSkuType(SkuType.COMMON.getCode());
            cartInfo.setPerLimit(skuInfo.getPerLimit());
            cartInfo.setImgUrl(skuInfo.getImgUrl());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setWareId(skuInfo.getWareId());
            cartInfo.setIsChecked(1);
            cartInfo.setStatus(1);
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());
        }

        //5.更新redis缓存
        hashOps.put(skuId.toString(),cartInfo);

        //设置有效时间
        this.setCartKeyExpire(cartKey);


    }

    //设置Key的过期时间
    private void setCartKeyExpire(String key){
        //expire 设置过期时间的方法 key  时长  时长的单位
        redisTemplate.expire(key,RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }


    //根据skuId删除购物车
    @Override
    public void deleteCart(Long skuId, Long userId) {
        //就是购物车输入从1 减 到 0之后 前端会调用删除redis数据的接口
        //购物车的数据在redis中 从购物车删除数据
        BoundHashOperations<String,String,CartInfo> hashOperations =
                redisTemplate.boundHashOps(this.getCartKey(userId));

        if (hashOperations.hasKey(skuId.toString())){
            //删除
            hashOperations.delete(skuId.toString());
        }
    }

    //清空购物车
    @Override
    public void deleteAllCart(Long userId) {
        String cartKey = this.getCartKey(userId);
        BoundHashOperations<String,String,CartInfo> hashOperations =
                redisTemplate.boundHashOps(cartKey);
        //得到内层的val
        List<CartInfo> values = hashOperations.values();
        //循环遍历删除
        for (CartInfo cartInfo : values) {
            hashOperations.delete(cartInfo.getUserId().toString());
        }
    }

    //批量删除购物车 skuId
    @Override
    public void batchDeleteCart(List<Long> skuIdList,Long userId) {
        String cartKey = this.getCartKey(userId);
        BoundHashOperations<String,String,CartInfo> hashOperations =
                redisTemplate.boundHashOps(cartKey);
        skuIdList.forEach(skuId ->{
            hashOperations.delete(skuId.toString());
        });

    }

    //购物车列表接口
    @Override
    public List<CartInfo> getCartList(Long userId) {
        //判断用户Id是否为空
        List<CartInfo> cartInfoList = new ArrayList<>();
        if (StringUtils.isEmpty(userId)){
            return cartInfoList;
        }
        //不为空 从redis获取购物车数据
        String cartKey = this.getCartKey(userId);
        BoundHashOperations<String,String,CartInfo> boundHashOperations =
                redisTemplate.boundHashOps(cartKey);
        cartInfoList = boundHashOperations.values();
        if (!CollectionUtils.isEmpty(cartInfoList)){
            //最后一个加入的 在一个显示
            //根据商品添加时间 降序
            cartInfoList.sort(new Comparator<CartInfo>() {
                @Override
                public int compare(CartInfo o1, CartInfo o2) {
                    return o1.getCreateTime().compareTo(o2.getCreateTime());
                }
            });
        }
        return cartInfoList;
    }


    //获取购物车选中的商品
    @Override
    public List<CartInfo> getCartCheckedList(Long userId) {
        //isChecked 这个属性判断是否被选中 1表示
        //当前购物车的内容是在Redis中
        //获取到key值
        String cartKey = this.getCartKey(userId);
        BoundHashOperations<String,String,CartInfo> boundHashOperations =
                redisTemplate.boundHashOps(cartKey);

        List<CartInfo> cartInfoList = boundHashOperations.values();
        //遍历 拿到isChecked 的集合
        List<CartInfo> cartInfoListNew = cartInfoList.stream().filter(cartInfo -> {
            return cartInfo.getIsChecked().intValue() == 1;
        }).collect(Collectors.toList());

        return cartInfoListNew;
    }

    //订单生成完成之后 根据userId删除购物车选中记录
    @Override
    public void deleteCartCheck(Long userId) {
        //1.根据userId查询选中购物车记录
        List<CartInfo> cartInfoList = this.getCartCheckedList(userId);

        //查询list集合遍历处理 得到每个skuId的集合
        List<Long> skuIdList = cartInfoList.stream().map(
                item -> item.getUserId()
        ).collect(Collectors.toList());

        //构建redis的key的值
        //hash类型 key
        String cartKey = this.getCartKey(userId);

        //根据key查询filed-value结构
        BoundHashOperations<String,String,CartInfo> boundHashOperations =
                redisTemplate.boundHashOps(cartKey);

        //根据file（skuId） 删除redis数据
        skuIdList.forEach(skuId ->{
            boundHashOperations.delete(skuId.toString());
        });
    }
}
